package btree;

import global.Convert;
import global.GlobalConst;
import global.PageId;
import global.RID;
import global.SystemDefs;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import diskmgr.DiskMgrException;
import diskmgr.FileIOException;
import diskmgr.InvalidPageNumberException;

import bufmgr.BufMgrException;
import bufmgr.BufferPoolExceededException;
import bufmgr.HashEntryNotFoundException;
import bufmgr.HashOperationException;
import bufmgr.InvalidFrameNumberException;
import bufmgr.PageNotReadException;
import bufmgr.PagePinnedException;
import bufmgr.PageUnpinnedException;
import bufmgr.ReplacerException;

public class BT implements GlobalConst {
	private static Exception localIOException;

	public static final int keyCompare(KeyClass paramKeyClass1,
			KeyClass paramKeyClass2) throws KeyNotMatchException {
		if (((paramKeyClass1 instanceof IntegerKey))
				&& ((paramKeyClass2 instanceof IntegerKey))) {
			return ((IntegerKey) paramKeyClass1).getKey().intValue()
					- ((IntegerKey) paramKeyClass2).getKey().intValue();
		}
		if (((paramKeyClass1 instanceof StringKey))
				&& ((paramKeyClass2 instanceof StringKey))) {
			return ((StringKey) paramKeyClass1).getKey().compareTo(
					((StringKey) paramKeyClass2).getKey());
		}

		throw new KeyNotMatchException(null, "key types do not match");
	}

	public static final int getKeyLength(KeyClass paramKeyClass)
			throws KeyNotMatchException, IOException {
		if ((paramKeyClass instanceof StringKey)) {
			ByteArrayOutputStream localByteArrayOutputStream = new ByteArrayOutputStream();
			DataOutputStream localDataOutputStream = new DataOutputStream(
					localByteArrayOutputStream);
			localDataOutputStream
					.writeUTF(((StringKey) paramKeyClass).getKey());
			return localDataOutputStream.size();
		}
		if ((paramKeyClass instanceof IntegerKey))
			return 4;
		throw new KeyNotMatchException(null, "key types do not match");
	}

	public static final int getDataLength(short paramShort)
			throws NodeNotMatchException {
		if (paramShort == 12)
			return 8;
		if (paramShort == 11)
			return 4;
		throw new NodeNotMatchException(null, "key types do not match");
	}

	public static final int getKeyDataLength(KeyClass paramKeyClass,
			short paramShort) throws KeyNotMatchException,
			NodeNotMatchException, IOException {
		return getKeyLength(paramKeyClass) + getDataLength(paramShort);
	}

	public static final KeyDataEntry getEntryFromBytes(byte[] paramArrayOfByte,
			int paramInt1, int paramInt2, int paramInt3, short paramShort)
			throws KeyNotMatchException, NodeNotMatchException,
			ConvertException {
		try {
			int i;
			Object localObject2;
			if (paramShort == 11) {
				i = 4;
				localObject2 = new IndexData(Convert.getIntValue(paramInt1
						+ paramInt2 - 4, paramArrayOfByte));
			} else if (paramShort == 12) {
				i = 8;
				RID localRID = new RID();
				localRID.slotNo = Convert.getIntValue(
						paramInt1 + paramInt2 - 8, paramArrayOfByte);
				localRID.pageNo = new PageId();
				localRID.pageNo.pid = Convert.getIntValue(paramInt1 + paramInt2
						- 4, paramArrayOfByte);
				localObject2 = new LeafData(localRID);
			} else {
				throw new NodeNotMatchException(null, "node types do not match");
			}
			Object localObject1;
			if (paramInt3 == 1) {
				localObject1 = new IntegerKey(new Integer(Convert.getIntValue(
						paramInt1, paramArrayOfByte)));
			} else if (paramInt3 == 0) {
				localObject1 = new StringKey(Convert.getStrValue(paramInt1,
						paramArrayOfByte, paramInt2 - i));
			} else {
				throw new KeyNotMatchException(null, "key types do not match");
			}
			return new KeyDataEntry((KeyClass) localObject1,
					(DataClass) localObject2);
		} catch (IOException localIOException) {
		}
		throw new ConvertException(localIOException, "convert faile");
	}

	public static final byte[] getBytesFromEntry(KeyDataEntry paramKeyDataEntry)
			throws KeyNotMatchException, NodeNotMatchException,
			ConvertException {
		try {
			int i = getKeyLength(paramKeyDataEntry.key);
			int j = i;
			if ((paramKeyDataEntry.data instanceof IndexData))
				i += 4;
			else if ((paramKeyDataEntry.data instanceof LeafData)) {
				i += 8;
			}
			byte[] arrayOfByte = new byte[i];

			if ((paramKeyDataEntry.key instanceof IntegerKey)) {
				Convert.setIntValue(((IntegerKey) paramKeyDataEntry.key)
						.getKey().intValue(), 0, arrayOfByte);
			} else if ((paramKeyDataEntry.key instanceof StringKey))
				Convert.setStrValue(
						((StringKey) paramKeyDataEntry.key).getKey(), 0,
						arrayOfByte);
			else {
				throw new KeyNotMatchException(null, "key types do not match");
			}
			if ((paramKeyDataEntry.data instanceof IndexData)) {
				Convert.setIntValue(
						((IndexData) paramKeyDataEntry.data).getData().pid, j,
						arrayOfByte);
			} else if ((paramKeyDataEntry.data instanceof LeafData)) {
				Convert.setIntValue(
						((LeafData) paramKeyDataEntry.data).getData().slotNo,
						j, arrayOfByte);
				Convert.setIntValue(
						((LeafData) paramKeyDataEntry.data).getData().pageNo.pid,
						j + 4, arrayOfByte);
			} else {
				throw new NodeNotMatchException(null, "node types do not match");
			}
			return arrayOfByte;
		} catch (IOException localIOException) {
		}
		throw new ConvertException(localIOException, "convert failed");
	}

	public static void printBTree(BTIndexPage headerPage)
			throws FileIOException, InvalidPageNumberException,
			DiskMgrException, ReplacerException, HashOperationException,
			PageUnpinnedException, InvalidFrameNumberException,
			PageNotReadException, BufferPoolExceededException,
			PagePinnedException, BufMgrException, KeyNotMatchException,
			NodeNotMatchException, ConvertException, IOException,
			HashEntryNotFoundException, ConstructPageException {
		// BTFileScan scan = new BTFileScan(null, null);
		// ArrayList<KeyDataEntry> data = scan.getAll();
		// for (int i = 0; i < data.size(); i++) {
		// System.out.println("key: " + data.get(i).key + "//  data: "
		// + data.get(i).data);
		// }
	}

	public static void printPage(PageId pageId, int keyType)
			throws ConstructPageException, ReplacerException,
			HashOperationException, PageUnpinnedException,
			InvalidFrameNumberException, PageNotReadException,
			BufferPoolExceededException, PagePinnedException, BufMgrException,
			IOException, KeyNotMatchException, NodeNotMatchException,
			ConvertException, HashEntryNotFoundException {
		BTSortedPage page = new BTSortedPage(pageId,keyType);
		RID rid = page.firstRecord();
		if(page.getSlotCnt()!=0){
		KeyDataEntry entry = BT.getEntryFromBytes(page.getpage(),
				page.getSlotOffset(rid.slotNo), page.getSlotLength(rid.slotNo),
				keyType, NodeType.INDEX);
		System.out.print(entry.key + " ");

		while ((rid = page.nextRecord(rid)) != null) {
			entry = BT.getEntryFromBytes(page.getpage(),
					page.getSlotOffset(rid.slotNo),
					page.getSlotLength(rid.slotNo), keyType, NodeType.INDEX);
			System.out.print(entry.key + " ");
		}
		System.out.println();
		}
		SystemDefs.JavabaseBM.unpinPage(page.getCurPage(), false);
	}

	public static void printAllLeafPages(BTIndexPage headerPage)
			throws FileIOException, InvalidPageNumberException,
			DiskMgrException, ReplacerException, HashOperationException,
			PageUnpinnedException, InvalidFrameNumberException,
			PageNotReadException, BufferPoolExceededException,
			PagePinnedException, BufMgrException, KeyNotMatchException,
			NodeNotMatchException, ConvertException, IOException, ConstructPageException, HashEntryNotFoundException {
		BTFileScan.setHead(headerPage);
		BTFileScan scan = new BTFileScan(null, null);
		ArrayList<KeyDataEntry> leaves = scan.getLeaf();
		for (int i = 0; i < leaves.size(); i++) {
			System.out.println("key: " + leaves.get(i).key + "//  data: "
					+ leaves.get(i).data);
		}
	}
}